﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DoFactory.GangOfFour.Abstract.RealWorld
{
    /// <summary>
    /// Provide an interface for creating families of related or dependent objects without 
    /// specifying their concrete classes. 
    /// 
    /// Proveer una Interface para crear familias de objetos con sus dependencias
    /// sin especificar sus clases concretas
    /// 
    /// Contexto: Debemos crear diferentes objetos, todos pertenecientes a la misma familia. 
    /// Por ejemplo: las librerías para crear interfaces gráficas suelen utilizar este patrón y cada familia sería un sistema operativo distinto. 
    /// Así pues, el usuario declara un Botón, pero de forma más interna lo que está creando es un BotónWindows o un BotónLinux, 
    /// por ejemplo.
    /// El problema que intenta solucionar este patrón es el de crear diferentes familias de objetos.
    /// El patrón Abstract Factory está aconsejado cuando se prevé la inclusión de nuevas familias de productos, 
    /// pero puede resultar contraproducente cuando se añaden nuevos productos o cambian los existentes,
    /// puesto que afectaría a todas las familias creadas.
    /// 
    /// </summary>
    class MainApp
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>
        public static void Main()
        {
            //ExampleBook exampleBook = new ExampleBook();
            //exampleBook.Start();
            // cambiando
            ExampleLuciano exampleLuciano = new ExampleLuciano();
            exampleLuciano.Arrancar();

        }
    }

    public class ExampleBook
    {
        public void Start()
        {
            // Create and run the African animal world
            ContinentFactory africa = new AfricaFactory();
            AnimalWorld world = new AnimalWorld(africa);
            world.RunFoodChain();

            // Create and run the American animal world
            ContinentFactory america = new AmericaFactory();
            world = new AnimalWorld(america);
            world.RunFoodChain();

            // Wait for user input
            Console.ReadKey();

        }
    }


    /// <summary>
    /// The 'AbstractFactory' abstract class
    /// </summary>
    abstract class ContinentFactory
    {
        public abstract Herbivore CreateHerbivore();
        public abstract Carnivore CreateCarnivore();
    }

    /// <summary>
    /// The 'ConcreteFactory1' class
    /// </summary>
    class AfricaFactory : ContinentFactory
    {
        public override Herbivore CreateHerbivore()
        {
            Console.WriteLine("Crear Ñandu");
            return new Nandu();
        }
        public override Carnivore CreateCarnivore()
        {
            Console.WriteLine("Crear Leon");
            return new Leon();
        }
    }

    /// <summary>
    /// The 'ConcreteFactory2' class
    /// </summary>
    class AmericaFactory : ContinentFactory
    {
        public override Herbivore CreateHerbivore()
        {
            Console.WriteLine("Crear Bisonte");
            return new Bisonte();
        }
        public override Carnivore CreateCarnivore()
        {
            Console.WriteLine("Crear Lobo");
            return new Lobo();
        }
    }

    /// <summary>
    /// The 'AbstractProductA' abstract class
    /// </summary>
    abstract class Herbivore
    {
    }

    /// <summary>
    /// The 'AbstractProductB' abstract class
    /// </summary>
    abstract class Carnivore
    {
        public abstract void Eat(Herbivore h);
    }

    /// <summary>
    /// The 'ProductA1' class
    /// </summary>
    class Nandu : Herbivore
    {
    }

    /// <summary>
    /// The 'ProductB1' class
    /// </summary>
    class Leon : Carnivore
    {
        public override void Eat(Herbivore h)
        {
            // Eat Wildebeest
            Console.WriteLine(this.GetType().Name +
              " se come el " + h.GetType().Name);
        }
    }

    /// <summary>
    /// The 'ProductA2' class
    /// </summary>
    class Bisonte : Herbivore
    {
    }

    /// <summary>
    /// The 'ProductB2' class
    /// </summary>
    class Lobo : Carnivore
    {
        public override void Eat(Herbivore h)
        {
            // Eat Bison
            Console.WriteLine(this.GetType().Name +
              " eats " + h.GetType().Name);
        }
    }

    /// <summary>
    /// The 'Client' class
    /// </summary>
    class AnimalWorld
    {
        private Herbivore _herbivore;
        private Carnivore _carnivore;

        // Constructor
        public AnimalWorld(ContinentFactory factory)
        {
            _carnivore = factory.CreateCarnivore();
            _herbivore = factory.CreateHerbivore();
        }

        public void RunFoodChain()
        {
            _carnivore.Eat(_herbivore);
        }
    }
}
